package com.yanqu.road.server.manger.activity.fellingtrees;

import com.yanqu.road.entity.activity.ActivityConfig;
import com.yanqu.road.entity.activity.ActivityInfo;
import com.yanqu.road.entity.activity.fellingtrees.FellingTreesEquip;
import com.yanqu.road.entity.activity.fellingtrees.FellingTreesRankEquipData;
import com.yanqu.road.entity.activity.fellingtrees.FellingTreesReward;
import com.yanqu.road.entity.activity.fellingtrees.FellingTreesUserData;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesElixirConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesLevelConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesMaterialsConfig;
import com.yanqu.road.entity.activity.fellingtrees.config.FellingTreesWeaponsConfig;
import com.yanqu.road.entity.enums.eActivityType;
import com.yanqu.road.entity.enums.eFellingTreesEquipType;
import com.yanqu.road.logic.bussiness.activity.FellingTreesBusiness;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.pb.activity.FellingTreesProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.gameplayer.GamePlayer;
import com.yanqu.road.server.gameplayer.module.activity.fellingtrees.FellingTreesModule;
import com.yanqu.road.server.manger.activity.NormalActivityMgr;
import com.yanqu.road.server.manger.player.GamePlayerMgr;
import com.yanqu.road.server.protocol.CrossProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.utils.RandomHelper;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

public class FellingTreesMgr extends TempMgr {

    private static Logger log = LogManager.getLogger(FellingTreesMgr.class.getName());

    private static FellingTreesConfig fellingTreesConfig;

    // 玩家榜单上的装备信息
    private final static Map<Integer, Map<Long, FellingTreesRankEquipData>> activityEquipMap = new ConcurrentHashMap<>();

    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    @Override
    public boolean save() {

        for (Map<Long, FellingTreesRankEquipData> value : activityEquipMap.values()) {
            for (FellingTreesRankEquipData data : value.values()) {
                if (data.isInsertOption()) {
                    FellingTreesBusiness.addFellingTreesRankEquipData(data);
                } else if (data.isUpdateOption()) {
                    FellingTreesBusiness.updateFellingTreesRankEquipData(data);
                }
            }
        }

        // 移除旧数据
        int curId = fellingTreesConfig == null ? -1 : fellingTreesConfig.getActivityInfo().getActivityId();
        Set<Integer> keySet = activityEquipMap.keySet();
        for (Integer activityId : keySet) {
            if (curId != activityId) {
                activityEquipMap.remove(activityId);
            }
        }

        return true;
    }

    public static void reloadActivityData() {
        getLogger().info("reload FellingTrees begin");

        // 拿活动
        List<ActivityInfo> list = NormalActivityMgr.getOpenActivityInfoList(eActivityType.FellingTrees.getValue());
        if (list.isEmpty()) {
            fellingTreesConfig = null;
            getLogger().info("reload FellingTrees finish, no activity in show time.");
            return;
        }
        ActivityInfo activityInfo = list.get(0);
        int activityId = activityInfo.getActivityId();

        Map<String, ActivityConfig> configMap = NormalActivityMgr.getActivityConfigMap(activityId);

        // 重新加载
        FellingTreesConfig config = new FellingTreesConfig();
        config.setActivityInfo(activityInfo);
        config.initActivityConfig(configMap);
        config.setElixirConfigMap(FellingTreesBusiness.getFellingTreesElixirConfigMap(activityId));
        config.setLevelConfigMap(FellingTreesBusiness.getFellingTreesLevelConfigMap(activityId));
        config.setMaterialsConfigMap(FellingTreesBusiness.getFellingTreesMaterialsConfigMap(activityId));
        config.setWeaponsConfigMap(FellingTreesBusiness.getFellingTreesWeaponsConfigMap(activityId));

        // 参数格式转化
        for (FellingTreesElixirConfig elixirConfig : config.getElixirConfigMap().values()) {
            elixirConfig.init();
        }
        for (FellingTreesLevelConfig levelConfig : config.getLevelConfigMap().values()) {
            levelConfig.init();
        }
        for (FellingTreesMaterialsConfig materialsConfig : config.getMaterialsConfigMap().values()) {
            materialsConfig.init();
        }
        for (FellingTreesWeaponsConfig weaponsConfig : config.getWeaponsConfigMap().values()) {
            weaponsConfig.init();
        }

        // 替换配置
        fellingTreesConfig = config;

        getLogger().info("reload FellingTrees finish, activityId {}.", activityId);

        // 在线玩家刷新
        for (GamePlayer player : GamePlayerMgr.getAllOnlinePlayer()) {
            player.getModule(FellingTreesModule.class).refreshData();
        }

    }

    public static FellingTreesConfig getFellingTreesConfig() {
        return fellingTreesConfig;
    }

    public static ActivityInfo getActivityInfo() {
        return fellingTreesConfig == null ? null : fellingTreesConfig.getActivityInfo();
    }

    private static int getDropEquipLevel(Random random, int treeLevel, boolean baoDi) {
        FellingTreesConfig config = getFellingTreesConfig();

        // 掉落等级配置
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(treeLevel);

        // 基础等级
        int baseLevel = levelConfig.getDropLevel() - levelConfig.getDropLevel() % config.getEquipDropK();

        // 浮动等级
        int floatLevel = 0;
        if (baoDi) {
            // 保底的等级是固定的
        } else {
            int index = RandomHelper.getRandomIndexByWeight(config.getEquipDropRandomWeight(), random);
            floatLevel = config.getEquipDropRandomLevel().get(index);
            floatLevel = floatLevel * config.getEquipDropY();
        }

        // 掉落范围限制
        int level = baseLevel + floatLevel;
        if (level < config.getMinDropEquipLevel()) {
            level = config.getMinDropEquipLevel();
        }
        if (level > config.getMaxDropEquipLevel()) {
            level = config.getMaxDropEquipLevel();
        }
        return level;
    }

    /**
     * 更新榜单装备
     */
    public static void updateRankEquip(int activityId, long userId, String param) {

        synchronized (activityEquipMap) {

            // 读库
            if (!activityEquipMap.containsKey(activityId)) {
                Map<Long, FellingTreesRankEquipData> map = FellingTreesBusiness.getFellingTreesRankEquipDataMap(activityId);
                activityEquipMap.put(activityId, map);
            }
            Map<Long, FellingTreesRankEquipData> map = activityEquipMap.get(activityId);

            // 生成数据
            if (!map.containsKey(userId)) {
                FellingTreesRankEquipData data = new FellingTreesRankEquipData(activityId, userId, param);
                data.setInsertOption();
                map.put(userId, data);
            }
            FellingTreesRankEquipData data = map.get(userId);

            // 修改数据
            data.setParam(param);
        }

    }

    /**
     * 看榜单装备
     */
    public static void seeRankEquip(int activityId, long reqServerId, long reqUserId, long seeUserId) {

        String param = null;
        Map<Long, FellingTreesRankEquipData> map = activityEquipMap.get(activityId);
        if (map != null) {
            FellingTreesRankEquipData data = map.get(seeUserId);
            if (data != null) {
                param = data.getParam();
            }
        }

        FellingTreesProto.FellingTreesSeeRankEquipRespMsg.Builder resp = FellingTreesProto.FellingTreesSeeRankEquipRespMsg.newBuilder();
        if (!StringUtils.isNullOrEmpty(param)) {
            resp.setRet(0);
            resp.setParam(param);
        } else {
            resp.setRet(GameErrorCode.E_FELLING_TREES_PARAM_ERROR);
        }

        FellingTreesProto.CrossFellingTreesSeeRankEquipRespMsg.Builder builder = FellingTreesProto.CrossFellingTreesSeeRankEquipRespMsg.newBuilder();
        builder.setActivityId(activityId);
        builder.setReqServerId(reqServerId);
        builder.setReqUserId(reqUserId);
        builder.setResp(resp);
        YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(CrossProtocol.C2_CROSS_FELLING_TREES_SEE_RANK_EQUIP_RESP, builder);
        GamePlayerMgr.sendPacket(0, yanQuMessage);
    }

    /**
     * 获取掉落法宝
     *
     * @return UID未设置值
     */
    public static List<FellingTreesEquip> getDropNormalEquipList(Random random, int topLevel, int treeLevel, List<Long> addition, boolean canBaodi) {

        FellingTreesConfig config = getFellingTreesConfig();
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(treeLevel);
        boolean baoDi = canBaodi && topLevel < treeLevel && levelConfig.getDropFirstWeapon() == 1; // 首次通关，且该关卡有保底

        // 掉落数量
        int dropCount;
        if (baoDi) {
            dropCount = 1;
        } else {
            List<Integer> countWeightList = new ArrayList<>(levelConfig.getDropWeaponProList());
            dropCount = RandomHelper.getRandomIndexByWeight(countWeightList, random);
        }
        if (dropCount == 0) {
            return new ArrayList<>();
        }

        // 保底品质
        int baoDiQua = baoDi ? config.getDropEquipGuaranteeQua() : 0;

        // 可掉落装备和权重
        List<Integer> equipList = new ArrayList<>();
        List<Integer> equipWeightList = new ArrayList<>();
        for (FellingTreesWeaponsConfig weaponsConfig : config.getWeaponsConfigMap().values()) {
            if (weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue() || weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue()) {
                continue; // 这里不掉落灵宝和道器
            }
            if (weaponsConfig.getQuality() < baoDiQua) {
                continue;
            }
            boolean canDrop = false;
            for (List<Integer> range : weaponsConfig.getDropLevelRangeList()) {
                if (range.get(0) <= treeLevel && treeLevel <= range.get(1)) {
                    canDrop = true;
                    break;
                }
            }
            if (canDrop) {
                long addiWeight = addition != null && weaponsConfig.getQuality() >= addition.get(1) ?
                        BigDecimal.valueOf(addition.get(0) * weaponsConfig.getWeight()).divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue()
                        : 0;
                equipList.add(weaponsConfig.getId());
                equipWeightList.add(weaponsConfig.getWeight() + (int) addiWeight);
            }
        }
        if (equipWeightList.stream().noneMatch(item -> item > 0)) {
            return new ArrayList<>(); // 如果权重没有大于0的，则不掉落
        }

        // 结果
        List<FellingTreesEquip> resultList = new ArrayList<>();
        for (int i = 0; i < dropCount; i++) {
            int index = RandomHelper.getRandomIndexByWeight(equipWeightList, random);
            int equipId = equipList.get(index);
            int level = getDropEquipLevel(random, treeLevel, baoDi);

            FellingTreesEquip equip = new FellingTreesEquip(-1, equipId, level, level, false);
            resultList.add(equip);
        }
        return resultList;
    }

    /**
     * 获取掉落药材
     *
     * @return -1表示没掉落
     */
    public static int getDropItem(Random random, int treeLevel) {
        FellingTreesConfig config = getFellingTreesConfig();

        // 没掉落
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(treeLevel);
        int dropWeight = levelConfig.getDropMedicialMaterial();
        if (random.nextInt(1000) >= dropWeight) {
            return -1;
        }

        List<Integer> idList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        for (FellingTreesMaterialsConfig materialsConfig : config.getMaterialsConfigMap().values()) {
            boolean canDrop = false;
            for (List<Integer> range : materialsConfig.getDropLevelRangeList()) {
                if (range.get(0) <= treeLevel && treeLevel <= range.get(1)) {
                    canDrop = true;
                    break;
                }
            }
            if (canDrop) {
                idList.add(materialsConfig.getId());
                weightList.add(materialsConfig.getWeight());
            }
        }

        // 随机
        if (idList.size() > 0) {
            int index = RandomHelper.getRandomIndexByWeight(weightList, random);
            return idList.get(index);
        }
        return -1;
    }

    /**
     * 获取掉落灵宝
     */
    public static void getDropSpecialEquip(Random random, int treeLevel, List<Long> addition, FellingTreesReward reward) {
        FellingTreesConfig config = getFellingTreesConfig();

        // 没掉落
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(treeLevel);
        int dropWeight = levelConfig.getDropSpiritBead();
        if (addition != null) {
            int addWeight = BigDecimal.valueOf(dropWeight * addition.get(0))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
            dropWeight += addWeight;
        }
        if (random.nextInt(1000) >= dropWeight) {
            return;
        }

        List<Integer> idList = new ArrayList<>();
        List<Integer> weightList = new ArrayList<>();
        for (FellingTreesWeaponsConfig weaponsConfig : config.getWeaponsConfigMap().values()) {
            if (weaponsConfig.getType() != 2) {
                continue;
            }
            boolean canDrop = false;
            for (List<Integer> range : weaponsConfig.getDropLevelRangeList()) {
                if (range.get(0) <= treeLevel && treeLevel <= range.get(1)) {
                    canDrop = true;
                    break;
                }
            }
            if (canDrop) {
                idList.add(weaponsConfig.getId());
                weightList.add(weaponsConfig.getWeight());
            }
        }

        // 随机
        if (idList.size() > 0) {
            int index = RandomHelper.getRandomIndexByWeight(weightList, random);
            int specialEquipId = idList.get(index);
            // 获得灵宝
            reward.getSpecialEquips().addProperty(specialEquipId, BigInteger.ONE);
        }
    }


    /**
     * 掉落月灵石
     */
    public static void getDropMoonStone(Random random, int treeLevel, List<Long> addition, FellingTreesReward reward) {
        FellingTreesConfig config = getFellingTreesConfig();

        // 没掉落
        FellingTreesLevelConfig levelConfig = config.getLevelConfigMap().get(treeLevel);
        int dropWeight = levelConfig.getDropMoonStone();
        if (addition != null) {
            int addWeight = BigDecimal.valueOf(dropWeight * addition.get(0))
                    .divide(BigDecimal.valueOf(1000), 0, BigDecimal.ROUND_UP).intValue();
            dropWeight += addWeight;
        }
        if (random.nextInt(1000) < dropWeight) {
            int moonStoneId = config.getDaoqiClearItemId();
            reward.getItems().addProperty(moonStoneId, BigInteger.ONE);
        }
    }

    /**
     * 掉落道器
     */
    public static void dropDaoQi(FellingTreesConfig config, int lv, Set<Integer> allDaoQiEquipId, FellingTreesReward reward) {
        for (FellingTreesWeaponsConfig weaponsConfig : config.getWeaponsConfigMap().values()) {
            if (weaponsConfig.getType() != 3) {
                continue;
            }
            int daoQiId = weaponsConfig.getId();
            if (allDaoQiEquipId.contains(daoQiId)) {
                continue;
            }
            if (Integer.parseInt(weaponsConfig.getDropLevel()) > lv) {
                continue;
            }
            allDaoQiEquipId.add(daoQiId);
            reward.getDaoQi().addProperty(daoQiId, BigInteger.ONE);
        }
    }


    public static boolean onlyOneEquip(int equipId) {
        FellingTreesConfig config = getFellingTreesConfig();
        if (config == null) {
            return false;
        }
        FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equipId);
        if (weaponsConfig == null) {
            return false;
        }
        return weaponsConfig.getType() == eFellingTreesEquipType.SpecialEquip.getValue()
                || weaponsConfig.getType() == eFellingTreesEquipType.DaoQi.getValue();
    }

    /**
     * 灵珠升到满级所需的消耗
     */
    public static long upgradeSpecialEquipMaxLevelCount(FellingTreesUserData userData, int equipId) {
        FellingTreesConfig config = getFellingTreesConfig();
        if (config == null) {
            return 0;
        }
        FellingTreesWeaponsConfig weaponsConfig = config.getWeaponsConfigMap().get(equipId);
        if (weaponsConfig == null) {
            return 0;
        }
        FellingTreesEquip equip = null;
        for (FellingTreesEquip temp : userData.getEquipMap().values()) {
            if (equipId == temp.getEquipId()) {
                equip = temp;
            }
        }
        if (equip == null) {
            return 0;
        }
        int maxLevel = config.getSpecialEquipMaxLevel();
        int curLv = equip.getLv();
        if (curLv >= maxLevel) {
            return 0;
        }
        // 获取当前等级到满级所需的消耗
        long totalCount = 0;
        while (curLv < maxLevel) {
            totalCount += config.getSpecialEquipUpgradeCost().get(curLv - 1);
            curLv++;
        }
        return totalCount;
    }

}
